#include "vectorutils.h"
#include <cassert>
#include <stdlib.h>
#include <sstream>
#include <iostream>
#include "../defines.h"






void VectorUtils::sumaDirecta(vector<byte>& v1, const vector<byte>& v2) {
    assert(v1.size() == v2.size());
    bool carry = false;
    for (int x = v1.size() - 1; x >= 0; x--) {
        byte pre = v1[x];
        v1[x] += ((byte) (carry) ? 1 : 0);
        carry = unsh(pre) > unsh(v1[x]);
        pre = v1[x];
        v1[x] += v2[x];
        carry = carry || unsh(pre) > unsh(v1[x]);
    }
    if(carry) {
        v1.insert(v1.begin(), 1);
    }
}

bool VectorUtils::equals(const vector<byte>& v1, const vector<byte> v2){
	if(v1.size() == v2.size()){
		vector<byte>::const_iterator it1, it2;
		it1 = v1.begin();
		it2 = v2.begin();
		while(it1 < v1.end() && it2 < v2.end()){
			if(*it1 != *it2){
				return false;
			}
			it1++;
			it2++;
		}
		return true;
	}
	return false;
}

void VectorUtils::restaDirecta(vector<byte> & minuendo, const vector<byte>& sustraendo){
    assert(minuendo.size() == sustraendo.size());
    unsigned int size = minuendo.size();
    bool borrow = false;
    for(int i = size - 1; i >= 0; i--) {
        byte pre = minuendo[i];
        minuendo[i] -= ((byte)(borrow)?1:0);
        borrow = unsh(pre) < unsh(minuendo[i]);
        pre = minuendo[i];
        minuendo[i] -= sustraendo[i];
        borrow = borrow || unsh(pre) < unsh(minuendo[i]);
    }
    assert(!borrow);
}


void VectorUtils::reemplazar(vector<byte> & v1, unsigned int pos, const vector<byte> & v2) {
	assert(pos + v2.size() <= v1.size());
	unsigned int i = pos;
	vector<byte>::const_iterator it = v2.begin();
	while(i < v1.size() && it < v2.end()){
		v1[i] = *it;
		it++;
		i++;
	}
	assert(!(i < v1.size() && it < v2.end()));
}

string VectorUtils::show(const vector<byte> & v1) {
    string result = "";
    for (unsigned int x = 0; x < v1.size(); x++) {
        if (x > 0)
            result += ".";
        stringstream ss;
        ss << unsh(v1[x]);
        result += ss.str();
    }
    return result;
}

nat sumar(nat sum1, nat sum2, nat & carry){
	sum1 += carry;
	carry = (sum1 >> 8)&0xff;
	sum1 &= 0xff;
	sum1 += sum2;
	carry += (sum1 >> 8)&0xff;
	sum1 &= 0xff;
	return sum1;
}

vector<byte> VectorUtils::multiplicacionDirecta(const vector<byte>& v1, const vector<byte> & v2){
	assert(v1.size() == v2.size());
	unsigned int size = v1.size();
	vector<nat> result(2*size, 0);
	unsigned int pos = size*2 - 1;
	nat carry = 0;
	for (int x = size - 1; x >= 0; x--) {
		nat value1 = unsh(v1[x]);
        unsigned int r = pos;
		for (int y = size - 1; value1 != 0 && y >= 0; y--) {
			nat value2 = unsh(v2[y]);
			result[r] = sumar(result[r], value2*value1, carry);
			r--;
		}
        // termino de pasar el carry
		while (carry != 0) {
			result[r] = sumar(result[r], 0, carry);
			r--;
		}
		pos--;
		assert(carry == 0);
	}

	vector<byte> res(2*size, 0);
	for (unsigned int x = 0; x < 2*size; x++) {
		if (result[x] > 255) {
			assert(false);
		}
		res[x] = result[x];
	}
	return res;
}



void VectorUtils::sacarCerosFinal(vector<byte> & v) {
    if(!v.empty()){
        vector<byte>::iterator it = v.end();
        it--;
        while(it >= v.begin() && *it == 0){
            it--;
        }
        it++;
        v.erase(it, v.end());
    }
}

unsigned int VectorUtils::sacarCerosPrincipio(vector<byte> & v){
	unsigned int res = 0;
    if(!v.empty()){
        vector<byte>::iterator it = v.begin();
        while(it < v.end() && *it == 0){
            it++;
            res++;
        }
        v.erase(v.begin(), it);
    }
	return res;
}

void VectorUtils::cortarMaxPrecision(vector<byte>& v, int lim) {
    assert(lim > 0);
    if(v.size() > lim){
        v.erase(v.begin() + lim, v.end());
    }
}